package com.meatball.iot.driver.doormagnet

import com.alibaba.fastjson2.JSON
import com.chinamobile.iot.pulsar.auth.AESBase64Utils
import com.chinamobile.iot.pulsar.auth.IoTConsumer
import com.chinamobile.iot.pulsar.auth.IoTMessage
import com.chinamobile.iot.pulsar.config.IoTConfig
import com.meatball.iot.common.ClientConnectionThreadPool
import com.meatball.iot.driver.doormagnet.data.DoorMagnetDto
import com.meatball.iot.driver.doormagnet.data.DuYunDto
import com.meatball.iot.driver.doormagnet.data.document.DoorMagnetDocument
import com.meatball.iot.driver.doormagnet.data.properties.SubscribeProperties
import com.meatball.iot.driver.doormagnet.enums.*
import com.meatball.iot.driver.doormagnet.repository.DoorMagnetRepository
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.util.*

@Service
class DoorMagnetService(
    private val properties: SubscribeProperties,
    private val doorMagnetRepository: DoorMagnetRepository
) {
    companion object {
        private val logger = LoggerFactory.getLogger(DoorMagnetService::class.java)
    }

    /**
     * 创建一个固定大小的线程池，用于处理客户端连接
     */
    private val executorService = ClientConnectionThreadPool.executorService()

    /**
     * TODO 开始服务
     *
     */
    fun startServer() {
        val iotConsumer = IoTConsumer.IOTConsumerBuilder.anIOTConsumer()
            .brokerServerUrl(IoTConfig.brokerSSLServerUrl)
            .iotAccessId(properties.iotAccessId)
            .iotSecretKey(properties.iotSecretKey)
            .subscriptionName(properties.iotSubscriptionName)
            .iotMessageListener {
                try {
                    val msgId = it.messageId
                    val publishTime = it.publishTime
                    val payload = String(it.data)
                    val iotMessage = JSON.parseObject(payload, IoTMessage::class.java)
                    val originalMsg = AESBase64Utils.decrypt(iotMessage.data, properties.iotSecretKey.substring(8, 24))

                    logger.info(
                        "门磁消费消息======>>>>>>> messageId={}, publishTime={},  payload={}",
                        msgId, publishTime, payload
                    )
                    logger.info("门磁原始消息:{}", originalMsg)
                    executorService.execute {
//                        saveData(originalMsg)
                        saveDuYunData(originalMsg)
                    }

                } catch (e: Exception) {
                    logger.error("处理消息时发生错误: {}", e.message)
                    e.printStackTrace()
                }
            }
            .build()
        iotConsumer.run()
    }

    private fun saveDuYunData(originalMsg: String) {
        val msg = JSON.parseObject(originalMsg, DoorMagnetDto::class.java)
        if (msg.msgType == MsgType.DATA_POINTS) {
            msg.subData.value?.let {
                // 注册序列化实现
                val data = JSON.parseObject(it.decodeHex(), DuYunDto::class.java)

                // 保存数据
                doorMagnetRepository.save(DoorMagnetDocument(
                    dataStreamId = msg.subData.dataStreamId,
                    deviceId = msg.subData.deviceId,
                    deviceName = msg.subData.deviceName,
                    imei = msg.subData.imei,
                    productId = msg.subData.productId,
                    time = msg.subData.time,
                    messageType = data.cmd,
                    eventType = data.event,
                    state = data.state,
                    batteryVoltage = data.vBat,
                    receivePower = data.csq,
                    rawData = originalMsg
                ))
            }
        }
    }

    /**
     * TODO 处理数据
     *
     * @param originalMsg 解密后数据
     */
    /*private fun saveData(originalMsg: String) {
        val msg = JSON.parseObject(originalMsg, DoorMagnetDto::class.java)
        if (msg.msgType == MsgType.DATA_POINTS) {
            msg.subData.value?.let {
                val data = base64ToHex(it.data)
                // 报警设备
                val alarmLocation = parseAlarmStatus(data.substring(0..1))
                // 事件类型
                val eventType = EventType.fromCode(data.substring(2..3))
                // 电池电压(v)
                val batteryVoltage = (data.substring(4..5).toInt(16) + 180) / 100.0
                // 温度(℃)
                val temperature = data.substring(6..7).toInt(16)
                // 信号功率值
                val receivePower = data.substring(8..9).toInt(16)
                // 保存数据
                doorMagnetRepository.save(DoorMagnetDocument(
                    dataStreamId = msg.subData.dataStreamId,
                    deviceId = msg.subData.deviceId,
                    deviceName = msg.subData.deviceName,
                    imei = msg.subData.imei,
                    productId = msg.subData.productId,
                    time = msg.subData.time,
                    alarmLocation = alarmLocation,
                    eventType = eventType,
                    batteryVoltage = batteryVoltage,
                    temperature = temperature,
                    receivePower = receivePower,
                    rawData = originalMsg
                ))
            }
        }
    }*/

    /**
     * TODO base64转hex
     *
     * @param base64String
     * @return
     */
    private fun base64ToHex(base64String: String): String {
        // 第一步：解码 Base64 字符串到二进制数据
        val binaryData = Base64.getDecoder().decode(base64String)

        // 第二步：将二进制数据转换为十六进制字符串
        return binaryData.joinToString("") { byte -> "%02x".format(byte) }
    }

    /**
     * TODO 报警状态
     *  将hex转为二进制并且按照大小端顺序读取报警状态
     *  bit0=前防拆;bit1=后防拆;bit2=门磁;bit3=INPUT1;bit4=INPUT2
     *
     * @param hexCode hex字符串
     */
    fun parseAlarmStatus(hexCode: String): List<AlarmLocation> {
        // 将十六进制字符串转换为至少8位的二进制字符串
        val binaryString = hexCode.toInt(16).toString(2).padStart(8, '0')

        // 用于保存激活报警的列表
        val activeAlarms = mutableListOf<AlarmLocation>()

        // 检查每一位，如果设置了相应的报警类型则添加到列表中
        if (binaryString[7] == '1') activeAlarms.add(AlarmLocation.FRONT_TAMPER)
        if (binaryString[6] == '1') activeAlarms.add(AlarmLocation.REAR_TAMPER)
        if (binaryString[5] == '1') activeAlarms.add(AlarmLocation.DOOR_SENSOR)
        if (binaryString[4] == '1') activeAlarms.add(AlarmLocation.INPUT1)
        if (binaryString[3] == '1') activeAlarms.add(AlarmLocation.INPUT2)

        // 返回激活的报警数组
        return activeAlarms
    }

    /**
     * TODO hex转字符串
     *
     * @return
     */
    private fun String.decodeHex(): String {
        require(length % 2 == 0) { "传入的hex长度不合法" }
        return String(
            chunked(2)
                .map { it.toInt(16).toByte() }
                .toByteArray()
        )
    }
}